﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Collections.Concurrent;

namespace CommonsLib.ORM
{
    public class ORMFunc
    {
        private const string NO_IDENTITY = "No Identity";

        private static ConcurrentDictionary<string, string> _dictKeyName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictForeignKeyName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictIdentityName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictDBname = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictTablename = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictFields = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictProps = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictSubTables = new ConcurrentDictionary<string, string>();

        public static string GetKeyField(Type objType)
        {
            string strKey =_dictKeyName.ContainsKey(objType.FullName)?  _dictKeyName[objType.FullName]:string.Empty;

            if (strKey.Length==0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strKey = GetName(objType, ObjAttr.KeyPropName,false);
                    if (string.IsNullOrEmpty(strKey))
                    {
                        throw new Exception(string.Format("Key {0} 不存在", ObjAttr.KeyPropName));
                    }
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strKey.Length==0)
                {
                    throw new Exception(objType.ToString() + ".DataTableAttribute没有设置Key属性。");
                }

                _dictKeyName[objType.FullName] = strKey;
            }
            return strKey;
        }

        public static string GetForeignKeyField(Type objType)
        {
            string strForeignKey = _dictForeignKeyName.ContainsKey(objType.FullName) ? _dictForeignKeyName[objType.FullName] : string.Empty;

            if (strForeignKey.Length == 0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {                    
                    strForeignKey = GetName(objType, ObjAttr.ForeignKeyPropName,false);
                    if (string.IsNullOrEmpty(strForeignKey))
                    {
                        throw new Exception(string.Format("ForeignKey {0} 不存在", ObjAttr.ForeignKeyPropName));
                    }
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strForeignKey.Length == 0)
                {
                    throw new Exception(objType.ToString() + ".DataTableAttribute没有设置ForeignKey属性。");
                }

                _dictForeignKeyName[objType.FullName] = strForeignKey;
            }
            return strForeignKey;
        }
        
        public static string GetTableName(Type objType)
        {
            string strTablename = _dictTablename.ContainsKey(objType.FullName) ? _dictTablename[objType.FullName] : string.Empty;  

            if (strTablename.Length==0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strTablename = ObjAttr.TableName;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strTablename.Length==0)
                {
                    throw new Exception(objType.ToString() + "没有设置TableName属性。");
                }

                _dictTablename[objType.FullName] = strTablename;
            }

            return strTablename;
        }

        public static string GetDBName(Type objType)
        {
            string strDBname = _dictDBname.ContainsKey(objType.FullName) ? _dictDBname[objType.FullName] : string.Empty;  

            if (strDBname.Length == 0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strDBname = ObjAttr.DBName;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strDBname.Length == 0)
                {
                    throw new Exception(objType.ToString() + "没有设置DBname属性。");
                }

                _dictDBname[objType.FullName] = strDBname;
            }

            return strDBname;
        }

        public static string GetIdentityField(Type objType)
        {
            string strIdentityName = _dictIdentityName.ContainsKey(objType.FullName) ? _dictIdentityName[objType.FullName] : string.Empty; 


            if (strIdentityName.Length == 0  )
            {
                strIdentityName = NO_IDENTITY;
                //反射设置ModelObject的属性
                PropertyInfo[] props = objType.GetProperties();
                DataFieldAttribute FieldAttr = null;

                object[] CustomAttributes;

                foreach (PropertyInfo prop in props)
                {
                    CustomAttributes = prop.GetCustomAttributes(typeof(DataFieldAttribute), false);
                    if (CustomAttributes.Length > 0)
                    {
                        FieldAttr = CustomAttributes[0] as DataFieldAttribute;
                        if (FieldAttr != null && FieldAttr.IsIdentity)
                        {
                            strIdentityName=FieldAttr.FieldName;
                        }
                    }

                }


                _dictIdentityName[objType.FullName] = strIdentityName;
            }


            return strIdentityName;
             
        }

        public static  string GetNames(Type objType,bool blnFields)
        {
            string strFields = _dictFields.ContainsKey(objType.FullName) ? _dictFields[objType.FullName] : string.Empty;
            string strProps = _dictProps.ContainsKey(objType.FullName) ? _dictProps[objType.FullName] : string.Empty; 

            if (strFields.Length == 0 || strProps.Length == 0)
            {
                List<string> lstFields = new List<string>();
                List<string> lstProps = new List<string>();
                //反射设置ModelObject的属性
                PropertyInfo[] props = objType.GetProperties();
                DataFieldAttribute FieldAttr = null;

                object[] CustomAttributes;
                
                foreach (PropertyInfo prop in props)
                {
                    CustomAttributes = prop.GetCustomAttributes(typeof(DataFieldAttribute), false);
                    if (CustomAttributes.Length > 0)
                    {
                        FieldAttr = CustomAttributes[0] as DataFieldAttribute;
                        if (FieldAttr != null)
                        {
                            lstFields.Add(FieldAttr.FieldName);
                            lstProps.Add(prop.Name);   
                        }
                    }

                }

                strFields =string.Join(",", lstFields.ToArray<string>());
                strProps =string.Join(",", lstProps.ToArray<string>());
                if (strFields.Length == 0)
                {
                    throw new Exception(objType.ToString() + "没有设置DataFieldAttribute属性。");
                }

                _dictFields[objType.FullName] = strFields;
                _dictProps[objType.FullName] = strProps;
            }

            if (blnFields)
            {
                return strFields;
            }
            else
            {
                return strProps;
            }
        }
     
        public static void SetValue(object modelObject, object objValue,string strName,bool blnField)
        {
            Type objType = modelObject.GetType();

            string[] arrFields = GetNames(objType, true).Split(',');
            string[] arrProps = GetNames(objType, false).Split(',');

            for (int i = 0; i < arrFields.Length; i++)
            { 
                if (    
                    (blnField && strName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                    ||
                    (!blnField && strName.Equals(arrProps[i], StringComparison.InvariantCultureIgnoreCase))
                    )
                {
                    PropertyInfo prop = modelObject.GetType().GetProperty(arrProps[i]);

                    prop.SetValue(modelObject, Convert.ChangeType(objValue, prop.PropertyType), null);
                    return;
                }
            }


        }

        /// <summary>
        /// 如果是Field,就得到Prop
        /// 反之亦然
        /// </summary>
        /// <param name="type"></param>
        /// <param name="strName"></param>
        /// <param name="blnField"></param>
        /// <returns></returns>
        public static string GetName(Type objType ,string strName,bool blnField)
        {

            string strFullName = objType.FullName;

            string[] arrFields = GetNames(objType, true).Split(',');
            string[] arrProps = GetNames(objType, false).Split(',');



            for (int i = 0; i < arrProps.Length; i++)
            { 
                if(blnField)
                {
                    if(strName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                    {
                        return arrProps[i];
                    }
                }
                else
                {
                    if(strName.Equals(arrProps[i], StringComparison.InvariantCultureIgnoreCase))
                    {
                        return arrFields[i];
                    }
                }
                 
            }
            return null;

        }

        public static void SetIdentityValue(object modelObject, object identityValue)
        {
            Type objType = modelObject.GetType();
            string strIdentityField = GetIdentityField(objType);
            if(!string.IsNullOrEmpty(strIdentityField)  && !strIdentityField.Equals(NO_IDENTITY))
            {
                SetValue(  modelObject,   identityValue,  strIdentityField,true);
            }
        }


        public static void Read(object ModelObject, System.Data.Common.DbDataReader rdr)
        {
            Read(ModelObject, rdr, false);
        }
        public static void Read(object ModelObject, System.Data.Common.DbDataReader rdr,bool blnFieldFilter)
        {
            Type objType=ModelObject.GetType();
            string[] arrFields = GetNames(objType, true).Split(',');
            string[] arrProps = GetNames(objType, false).Split(',');
            for (int i = 0; i < rdr.FieldCount; i++)
            {
                //反射设置ModelObject的属性
                string strPropName = string.Empty;
                if (blnFieldFilter)
                {
                    string strFieldName = rdr.GetName(i);
                    for (int j = 0; j < arrFields.Length; j++)
                    {
                        if (arrFields[j].Equals(strFieldName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            strPropName = arrProps[j];
                            break;
                        }
                    }
                }
                else
                {
                    strPropName = arrProps[i];
                }
                if (strPropName.Length == 0) continue;

                PropertyInfo prop = ModelObject.GetType().GetProperty(strPropName);
                 
                object obj = (rdr[i] == DBNull.Value) ? null
                    : ((prop.PropertyType == typeof(string)) ? rdr.GetString(i).TrimEnd() : Convert.ChangeType(rdr[i], prop.PropertyType));
                
                 prop.SetValue(ModelObject,obj, null);
            }
        }

        public static object[] GetValues(object ModelObject, string strSelectFields)
        {
            return GetValues(ModelObject, strSelectFields, true);
        }
        public static object[] GetValues(object ModelObject, string strSelectFields, bool blnIgnoreIdentity)
        {
            Type objType = ModelObject.GetType();
            string[] arrFields = strSelectFields.Split(',');
            
            object[] datas = new object[arrFields.Length];
            string strIdentityName = string.Empty;
            if (blnIgnoreIdentity)
            {
                strIdentityName = GetIdentityField(objType);
            }
            for (int i = 0; i < arrFields.Length; i++)
            {

                PropertyInfo prop = objType.GetProperty(GetName(objType, arrFields[i],true));
                if (!(blnIgnoreIdentity && strIdentityName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase)))
                {
                    datas[i] = prop.GetValue(ModelObject, null);
                }
            }

            return datas;
        }
        public static object GetValue(object ModelObject, string strName, bool blnField)
        {
            Type objType = ModelObject.GetType();
            string[] arrFields = GetNames(objType, true).Split(',');
            string[] arrProps = GetNames(objType, false).Split(',');


            for (int i = 0; i < arrFields.Length; i++)
            {
                if (
                    (blnField && strName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                    ||
                    (!blnField && strName.Equals(arrProps[i], StringComparison.InvariantCultureIgnoreCase))
                    )
                {

                    PropertyInfo prop = ModelObject.GetType().GetProperty(arrProps[i]);

                    return prop.GetValue(ModelObject, null);
                }

            }

            return null;
        }
        public static object GetKeyValue(object ModelObject)
        {
            Type objType = ModelObject.GetType();
            return GetValue(  ModelObject, GetKeyField(objType), true);
            
        }

        
        //public static string GetSubTables(Type objType)
        //{
        //    string strSubTables = _dictSubTables.ContainsKey(objType.FullName) ? _dictSubTables[objType.FullName] : string.Empty;


        //    if (strSubTables.Length == 0)
        //    {
        //        List<string> lstSubTables = new List<string>();

        //        //反射设置ModelObject的属性
        //        System.Reflection.PropertyInfo[] props = objType.GetProperties();
        //        SubTableAttribute SubTableAttr = null;

        //        object[] CustomAttributes;

        //        foreach (System.Reflection.PropertyInfo prop in props)
        //        {
        //            CustomAttributes = prop.GetCustomAttributes(typeof(SubTableAttribute), false);
        //            if (CustomAttributes.Length > 0)
        //            {
        //                SubTableAttr = CustomAttributes[0] as SubTableAttribute;
        //                if (SubTableAttr != null)
        //                {
        //                    lstSubTables.Add(string.Format("{0}|{1}|{2}", prop.Name, SubTableAttr.OrgPropName, SubTableAttr.DestPropName));
        //                }
        //            }

        //        }

        //        strSubTables = string.Join(",", lstSubTables.ToArray<string>());

        //        if (strSubTables.Length == 0)
        //        {
        //            strSubTables = " ";
        //        }

        //        _dictSubTables[objType.FullName] = strSubTables;

        //    }


        //    return strSubTables.Trim();

        //}
    }
}
